package umls.interfaces.pubmed.server;

import java.io.BufferedInputStream;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionException;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;

import metamap.proxy.client.MetamapClient;

import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.fbk.it.hlt.jlsi.DomainTermSimilarity;
import org.fbk.it.hlt.jlsi.Percentili;
import org.fbk.it.hlt.jlsi.ScoreTermMap;
import org.fbk.it.hlt.jlsi.TermNotFoundException;
import org.fbk.it.hlt.jlsi.data.TextCorpusReader;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;

import umls.data.GenKeywords;
import umls.data.jaxb.ExpandedTermsType;
import umls.data.jaxb.TermType;
import umls.interfaces.MySql;
import umls.interfaces.Pathways.Pathways;
import umls.interfaces.pubmed.jaxb.PubMedProxyImpl;


//@Stateful
//@Addressing
@WebService(targetNamespace = "http://jaxws.server.pubmed.interfaces.umls/", name = "PubProxy")
public class PubMedImpl implements PubMedProxyImpl {
	// private BlockingQueue<AbstractMapper> coda;
	//public static StatefulWebServiceManager<PubMedProxyImpl> manager;
	// private final Semaphore available = new Semaphore(10, true);
	static Logger logger = Logger.getLogger("umls.interfaces.pubmed.server");
	
	static MetamapClient mc;
	ExecutorService download_service;
	ExecutorService flusher_service;
	static MySql database;

	public PubMedImpl() {
		
		String host = "bioeda2.polito.it";
		String user = "abate";
		String pass = "7prova7";
		String dbname = "umls";
		PropertyConfigurator.configure("MedServiceData/log-config.txt");
		// String address = "http://localhost:7071/Metamap";
		String address = "http://bioeda2.polito.it:7071/Metamap";
		try {
			mc = new MetamapClient(address);
		} catch (Exception e) {
			System.out.println("Nessun server metamap all'indirizzo " + address
					+ "\nTermine programma");
			logger.error("Nessun server metamap all'indirizzo " + address);
			System.exit(-1);
		}
		try {
			database = new MySql(host, user, pass, dbname);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		download_service = java.util.concurrent.Executors
				.newFixedThreadPool(20);
		flusher_service = java.util.concurrent.Executors.newFixedThreadPool(15);
		logger.debug("Costruttore server eseguito");
		System.out.println("Server up");
	}

	
	/* (non-Javadoc)
	 * @see umls.interfaces.pubmed.server.PubMedInterface#getPreferredNames(java.lang.String, java.lang.String[])
	 */
	
	
	@WebMethod
	public String[] getPreferredNames(
			@WebParam(name = "process") String process,
			@WebParam(name = "genes")String[] genes) {
		process = process.toLowerCase();
		List<String> mappedProcess = getMappedDef(process);
		long start_time = new Date().getTime();
		List<Future> termination = new LinkedList<Future>();
		for (String gene : genes) {
			try {
				for (String aui : getSynonymsAUI(gene)) {
					System.out.println(database.getDefFromAUI(aui)
							+ "\nFine Ricerca sinonimi");

				}
			} catch (SQLException e) {

			}
			BlockingQueue<MetamapOutput> q = new LinkedBlockingQueue<MetamapOutput>(
					20);
			File output_dir = new File(System.getProperty("user.home")
					+ "/pubmed_result/" + gene + "_" + process + "/");
			output_dir.mkdirs();
			logger.trace("Creata cartella " + output_dir.getAbsolutePath());
			try {
				getPathwaysGenes(process, output_dir);
			} catch (IOException e1) {
				System.out.println("Errore PathWays: controlla log");
				logger
						.error("Errore: impossibile ottenere info certe da pathways: "
								+ e1.getMessage());
			}
			GenKeywords expander = new GenKeywords("MedServiceData/confsem.txt");
			ExpandedTermsType expanded_tree = null;
			try {
				expanded_tree = expander.generate(gene, process);
			} catch (SQLException e) {
				e.printStackTrace();
			}
			logger.trace("Espansione ha generato "
					+ expanded_tree.getTerm().size()
					+ " termini per la ricerca " + gene + " " + process);
			for (TermType term : expanded_tree.getTerm()) {
				String[] arr = { term.getTerm1().replace(" ", "+"),
						term.getTerm2().replace(" ", "+"),
						term.getTerm3().replace(" ", "+") };
				 BeanFactory ctx = new XmlBeanFactory(new ClassPathResource("beans.xml"));
				UncachedMapper mapper = new CachedAbstractMapper(q, arr);
				FileFlusher writer = new FileFlusher(q, output_dir
						.getAbsolutePath());
				try {
					// coda.put(new AbstractMapper(q,arr));
					download_service.execute(mapper);

					termination.add(flusher_service.submit(writer));
				} catch (RejectedExecutionException e) {
					e.printStackTrace();
				}
			}
		}
		for (Future f : termination)
			try {
				f.get();
			} catch (InterruptedException e1) {

				e1.printStackTrace();
			} catch (ExecutionException e1) {

				e1.printStackTrace();
			}

		logger.trace("Fine download documenti, attendo il completamento");

		for (String gene : genes) {
			try {

				String path = System.getProperty("user.home")
						+ "/pubmed_result/" + gene + "_" + process;
				writeDef(mappedProcess, path);
				Svdlibc.genSparseTable(new File(path));
				Svdlibc.getDomainTermSimilarity(process, path + "_matrix/");
			} catch (IOException e) {

				e.printStackTrace();
			}
		}
		long end_time = new Date().getTime();
		logger.debug("Completato in " + (end_time - start_time) / 1000
				+ " secondi");
		System.out.println("Completato in " + (end_time - start_time) / 1000
				+ " secondi");
		return null;
	}

	private boolean writeDef(List<String> values, String output_dir) {
		File f = new File(output_dir + "/DEFs.txt");
		FileWriter output;
		try {
			output = new FileWriter(f);
			for (String s : values) {
				output.append(s + "\n");
			}
			output.flush();
			output.close();
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		}
		return true;

	}

	/* (non-Javadoc)
	 * @see umls.interfaces.pubmed.server.PubMedInterface#getMappedPatwaysGene(java.lang.String)
	 */
	@Override
	public List<String> getMappedPatwaysGene(String term){
		List<String> result = new LinkedList<String>();
	//String term = request.getParameter("process");	
	StringBuilder sb = new StringBuilder();
	List<String> genes= null;
	try {
		genes = Pathways.getGenes(term);
	} catch (IOException e1) {
		return result;
		
	}
	for (int i = 0; i < genes.size(); i++) {
		sb.append(genes.get(i) + " ");
		if (((i + 1) % 10) == 0 || i == genes.size() - 1) {
			Future<List<String>> res = MetamapClient.delayedQuery(sb
					.toString());
			sb = new StringBuilder();
			try {
				for (String metamap_string : res.get()) {
					result.add(metamap_string + "\n");
				}

			} catch (InterruptedException e) {

				e.printStackTrace();
			} catch (ExecutionException e) {

				e.printStackTrace();
			}		
		}
		}
	return result;
}
	private void getPathwaysGenes(String process, File output_dir)
			throws IOException {
		File f = new File(output_dir + "/dati_pathways.txt");
		FileWriter output;
		try {
			output = new FileWriter(f);
		} catch (IOException e1) {

			e1.printStackTrace();
			return;
		}
		List<String> mappedgenes = getMappedPatwaysGene(process);
					for (String metamap_string : mappedgenes ) {
						output.append(metamap_string + "\n");
					
		}
		output.close();
	}



	/* (non-Javadoc)
	 * @see umls.interfaces.pubmed.server.PubMedInterface#getUMLSDef(java.lang.String)
	 */
	@Override
	public List<String> getUMLSDef(String term) {
		List<String> result = new LinkedList<String>();
		try {
			database.connect();
		
		List<String> CUIs = database.searchCUI(term);
		for (String s : CUIs) {
			result.addAll(database.getDescriptionFromCui(s));
		}
		} catch (SQLException e) {

			e.printStackTrace();
		}
		//return result;
		return  result;
	}

	private List<String> getMappedDef(String term) {
		List<String> result = new LinkedList<String>();
		for (String s : getUMLSDef(term)) {
			result.addAll(MetamapClient.blockingQuery(s));
		}
		return result;

	}



	String[] getSynonymsAUI(String term) throws SQLException {
		database.connect();
		List<String> result = new LinkedList<String>();
		List<String> AUIs = database.searchAUI(term);
		for (String s : AUIs) {
			try {
				result.add(database.getDefFromAUI(s));
			} catch (NoSuchElementException e) {
				System.out.println("Nessuna def per l'aui: " + s);
			}
		}
		return (String[]) result.toArray();

	}

	/* (non-Javadoc)
	 * @see umls.interfaces.pubmed.server.PubMedInterface#getAffinity(java.lang.String, java.lang.String)
	 */
	@Override
	public int getAffinity(String gene, String process) {

		return 0;
	}


	@Override
	public List<String> getPreferredNames(String process, List<String> genes) {
		// TODO Auto-generated method stub
		return null;
	}
}
